/*
 * Copyright (c) 2021 ExtremeVision Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef JI_SAMPLEDETECTOR_HPP
#define JI_SAMPLEDETECTOR_HPP
#include <string>
#include <opencv2/core/mat.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <openvino/openvino.hpp>

#include "ji.h"
#include "ji_utils.h"
#include "WKTParser.h"
#include "Configuration.hpp"

/**
 * 本demo采用基于YOLOv5的COCO数据集目标检测算法，基于openvino推理
 * SampleDetetctor类是完全可自定义的算法类，名字可以修改，在设计时注意与ji.cpp配合，能实现ji.cpp中相应的接口函数即可！！！
 */

#define STATUS int
using namespace std;
using namespace cv;
using namespace ov;

typedef struct
    {
        float prob;
        std::string name;
        cv::Rect rect;
    } Object;

class SampleDetector
{

public:
    /*
     * @breif 检测器构造函数     
    */ 
    SampleDetector();
    
    /*
     * @breif 检测器析构函数     
    */ 
    ~SampleDetector();
    
    /*
     * @breif 初始化检测器相关的资源
     * @param strModelName 检测器加载的模型名称     
     * @param thresh 检测阈值
     * @return 返回结果, STATUS_SUCCESS代表调用成功
    */ 
    STATUS Init(const std::string &strModelName, float thresh);

    /*
     * @breif 去初始化,释放模型检测器的资源     
     * @return 返回结果, STATUS_SUCCESS代表调用成功
    */ 
    STATUS UnInit();
    
    /*
     * @breif 根据送入的图片进行模型推理, 并返回检测结果
     * @param inFrame 输入图片
     * @param result 检测结果通过引用返回
     * @return 返回结果, STATUS_SUCCESS代表调用成功
    */
    STATUS ProcessImage(Mat &inFrame, std::vector<Object> &result, float thresh = 0.15);

public:
    // 接口的返回值定义
    static const int ERROR_BASE = 0x0200;
    static const int ERROR_INPUT = 0x0201;
    static const int ERROR_INIT = 0x0202;
    static const int ERROR_PROCESS = 0x0203;
    static const int STATUS_SUCCESS = 0x0000;   
private:    
    void nms(vector<Object>& inputBoxes);
    vector<string> classes;
    int num_class;
    bool decode_outputs(const float *outs, vector<Object>& detected_objects, const float scale, const int img_w, const int img_h);

    //存储初始化获得的可执行网络
    std::shared_ptr<ov::Model> model{nullptr};
    CompiledModel compiled_model;
    InferRequest infer_request;
    Tensor input_tensor;
    
    //参数区
    const string device_name = "CPU";
    const int mInpWidth = 640;
    const int mInpHeight = 640;
    float mThresh;                //置信度阈值,计算方法是框置信度乘以物品种类置信度
    float nms_area_threshold;  //nms最小重叠面积阈值
};

#endif //JI_SAMPLEDETECTOR_HPP
